#include "rads_guard.hpp"
// 全局原子变量，用于线程间的通信
std::atomic<bool> should_stop(false);
std::condition_variable cv;
std::mutex mtx;

//
ros::Publisher pub2api;
std::atomic<bool> should_ota(true);
VersionCheck vercheck;

// OTA升级服务（设计查询，比对版本号，下载，更新）
void threadOta(ros::Publisher _pub,rads::rads_versions _vers)
{
    bool request_ota = true;
    bool need_ota = false;
    int ota_counter = 0;
    while(request_ota && !should_stop.load())
    {
        _vers.header.stamp = ros::Time::now();
        _vers.header.frame_id = "nyd-version";
        _vers.ack = 0;
        if(!vercheck.ver_network_ok)_pub.publish(_vers);
        if(!vercheck.ver_kernel_ok)pub2api.publish(_vers);
        ota_counter++;
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
        if(vercheck.ver_kernel_ok && vercheck.ver_network_ok)
        {
            request_ota = false;
            std::string local_version = vercheck.kerner_vers.versions[0].major_minor_patch;
            std::string network_version = vercheck.network_vers.versions[0].major_minor_patch;
            ROS_INFO("locahost version = %s",local_version.c_str());
            ROS_INFO("network  version = %s,down = %s",network_version.c_str(),vercheck.network_vers.versions[0].temp_down_path.c_str());
            int result = compareVersions(network_version, local_version);
            if(result > 0)
            {
                ROS_INFO("The system is requesting an upgrade from %s to %s.",local_version.c_str(),network_version.c_str());
				need_ota = true;
            }
        }else{
            if(ota_counter > 10){
                request_ota = false;
                {
                    /*
                    std::vector<std::string> packages = splitStr(vercheck.network_vers.versions[0].temp_down_path,'/');
                    std::string path = "/home/jpc/catkin_ws/install/share/rads/ota/" + packages.back();
                    std::string cmd = "curl -o " + path + " " + vercheck.network_vers.versions[0].temp_down_path + " 2>/dev/null";
                    ROS_WARN("cmd = %s.",cmd.c_str());
                    system(cmd.c_str());
                     */
                }
                ROS_WARN("This update request failed due to a network or local service problem");
            }
        }
    }
    should_ota.store(need_ota);
}

// 获取版本信息
void version_callback(const rads::rads_versions& _vers)
{
    switch(_vers.ack)
    {
        case 1:
            {
                vercheck.ver_kernel_ok = true;
                vercheck.kerner_vers = _vers;
                ROS_INFO("network version = %s",vercheck.kerner_vers.versions[0].major_minor_patch.c_str());
            }
            break;
        default:break;
    }
}

// 获取版本信息(network)
void netversion_callback(const rads::rads_versions& _vers)
{
    switch(_vers.ack)
    {
        case 1:
            {
                vercheck.ver_network_ok = true;
                vercheck.network_vers = _vers;
                ROS_INFO("network version = %s,down_link = %s",vercheck.network_vers.versions[0].major_minor_patch.c_str(),vercheck.network_vers.versions[0].temp_down_path.c_str());
            }
            break;
        default:break;
    }
}


void threadguard(rads::rads_guard& _guard)
{
    while(!should_stop.load())
    {
        std::vector<long> prevCpuTimes = parseCpuTimes(getFirstLineOfFile("/proc/stat"));
        std::this_thread::sleep_for(std::chrono::seconds(1));
        std::vector<long> currCpuTimes = parseCpuTimes(getFirstLineOfFile("/proc/stat"));
        _guard.cpu_usage = calculateCpuUsage(prevCpuTimes, currCpuTimes);
        std::unordered_map<std::string, long> meminfo = parseMeminfo("/proc/meminfo");
        double memoryUsage = calculateMemoryUsage(meminfo);
        _guard.memery_usage = 100 - memoryUsage;
        if(should_stop.load())break;
        if(!isProcessRunning(NODE_TBOX_EXECU) && !should_stop.load())
        {
            if(!isNodeRunning(NODE_TBOX) && !should_stop.load())
            {
                if(restartNode(buildLaunchCommand(PACKAGE_NAME,NODE_TBOX_EXECU)))
                    ROS_INFO("rosnode [ %s ] restart successful.",NODE_TBOX);
            }else{
                system("yes | rosnode cleanup");
            }
            _guard.tbox_alive = 0;
        }else{
            _guard.tbox_alive = 1;
        }
        if(!isProcessRunning(NODE_RTK_EXECU) && !should_stop.load())
        {
            if(!isNodeRunning(NODE_RTK) && !should_stop.load())
            {
                if(restartNode(buildLaunchCommand(PACKAGE_NAME,NODE_RTK_EXECU)))
                    ROS_INFO("rosnode [ %s ] restart successful.",NODE_RTK);
            }else{
                system("yes | rosnode cleanup");
            }
            _guard.rtk_alive = 0;
        }else{
            _guard.rtk_alive = 1;
        }
        if(!isProcessRunning(NODE_DRIVE_EXECU) && !should_stop.load())
        {
            if(!isNodeRunning(NODE_DRIVE) && !should_stop.load())
            {
                if(restartNode(buildLaunchCommand(PACKAGE_NAME,NODE_DRIVE_EXECU)))
                    ROS_INFO("rosnode [ %s ] restart successful.",NODE_DRIVE);
            }else{
                system("yes | rosnode cleanup");
            }
            _guard.drive_alive = 0;
        }else{
            _guard.drive_alive = 1;
        }
        if(!isProcessRunning(NODE_SLAM_EXECU) && !should_stop.load())
        {
            if(!isNodeRunning(NODE_SLAM) && !should_stop.load())
            {
                if(restartNode(buildLaunchCommand(PACKAGE_NAME,NODE_SLAM_EXECU)))
                    ROS_INFO("rosnode [ %s ] restart successful.",NODE_SLAM);
            }else{
                system("yes | rosnode cleanup");
            }
            _guard.slam_alive = 0;
        }else{
            _guard.slam_alive = 1;
        }


        /**if(!isProcessRunning(NODE_BUSINESS_EXECU) && !should_stop.load())
        {
            if(!isNodeRunning(NODE_BUSINESS) && !should_stop.load())
            {
                if(restartNode(buildLaunchCommand(PACKAGE_NAME,NODE_BUSINESS_EXECU)))
                    ROS_INFO("rosnode [ %s ] restart successful.",NODE_BUSINESS);
            }else{
                system("yes | rosnode cleanup");
            }
           _guard.business_alive = 0;
        }else{
           _guard.business_alive = 1;
        }**/


    }
}

// 信号处理函数
void signalHandler(int signum) {
    if(SIGINT == signum){
        ROS_INFO("[Guard] Interrupt signal (%d) received. Shutting down...", signum);
        std::lock_guard<std::mutex> lck(mtx);
        should_stop.store(true);
        cv.notify_all();
        ros::shutdown();
    }
}

// 信号处理函数
void signaltermHandler(int signum)
{
    /*
    if(SIGTERM == signum){
        ROS_INFO("[Guard]<term> Interrupt signal (%d) received. Shutting down...", signum);
        std::lock_guard<std::mutex> lck(mtx);
        should_stop.store(true);
        cv.notify_all();
    }
     */
}

int main(int argc, char **argv)
{
    ROS_INFO("[Guard] Starting....");
	ros::init(argc, argv, NODE_GUARD);
	ros::NodeHandle nh;
    vercheck.ver_kernel_ok = false;
    vercheck.ver_network_ok = false;
    // 请求本地系统版本信息
    rads::rads_versions vers;
    // 设置信号处理函数
    signal(SIGINT, signalHandler);
    signal(SIGTERM, signaltermHandler);
    rads::rads_guard _guard;
    _guard.system_version = getSystemVersion();
    _guard.kernel_version =  getKernelVersion();
    _guard.robot_version = getRobotVersion();
    _guard.api_alive = 0;
    _guard.business_alive = -1;
    _guard.database_alive = -1;
    _guard.drive_alive = 0;
    _guard.rtk_alive = 0;
    _guard.slam_alive = 0;
    _guard.tbox_alive = 0;
    _guard.screen_alive = -1;
    _guard.map_alive = -1;
    ROS_INFO("[Guard] requesting version number");
    // 对全系统发布系统信息
    ros::Publisher p = nh.advertise<rads::rads_guard>("/pradsguard", QUEUE_SIZE);
    // 向本系统发布版本信息
    ros::Publisher p2 = nh.advertise<rads::rads_versions>("/pradsversion", QUEUE_SIZE);
    // 向API服务中心发布版本请求
    pub2api = nh.advertise<rads::rads_versions>("/radsversion2api", QUEUE_SIZE);
    // 订阅系统的版本信息(localhost)
    ros::Subscriber s = nh.subscribe("/sradsversion", QUEUE_SIZE,version_callback);
    // 订阅系统的版本信息(network)
    ros::Subscriber s2 = nh.subscribe("/radsversionapi", QUEUE_SIZE,netversion_callback);
    // OTA线程检测
    std::thread t_ota(threadOta,std::ref(p2),std::ref(vers));
    // 进程监控
    std::thread t_guard(threadguard,std::ref(_guard));
	ros::Rate rate(1);
	while (nh.ok()  && !should_stop.load())
	{
        _guard.header.stamp = ros::Time::now();
        _guard.header.frame_id = "nyd-guard";
        p.publish(_guard);
		ros::spinOnce();
		rate.sleep();
	}
    if(t_ota.joinable())t_ota.join();
    if(t_guard.joinable())t_guard.join();
	return 0;
}
